/*
 * 创建日期 2004-9-26
 *
 * 更改所生成文件模板为
 * 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
package com.ctsi.commons.util.crypto;

import com.ctsi.commons.util.GeneralException;

import javax.crypto.*;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;

/**
 * @author Administrator
 *
 *         更改所生成类型注释的模板为 窗口 > 首选项 > Java > 代码生成 > 代码和注释
 */
public class DesCrypt implements SymmetryCrypt {
	private int deaultKeySize = 168;

	public void setDeaultKeySize(int deaultKeySize) {
		this.deaultKeySize = deaultKeySize;
	}

	private String algorithm = "DESede";

	@Override
	public String getAlgorithm() {
		return algorithm;
	}

	public void setAlgorithm(String algorithm) {
		this.algorithm = algorithm;
	}

	private String transformation = "DESede/CBC/PKCS5Padding";

	@Override
	public String getTransformation() {
		return transformation;
	}

	public void setTransformation(String transformation) {
		this.transformation = transformation;
	}

	@Override
	public int getDeaultKeySize() {

		return deaultKeySize;
	}

	@Override
	public SecretKey generateKey() throws Exception {
		return generateKey(getDeaultKeySize(), null);
	}

	@Override
	public SecretKey generateKey(int size, SecureRandom secr) throws Exception {
		KeyGenerator keyGen = KeyGenerator.getInstance(getAlgorithm());
		if (secr != null) {
			keyGen.init(size, secr); // 初始化
		} else {
			keyGen.init(size); // 初始化
		}

		// DES算法必须是56位
		// DESede算法可以是112位或168位
		// AES算法可以是128、192、256位

		return keyGen.generateKey();
	}

	public byte[] encrypt(SecretKey key, byte[] bytes) throws GeneralException {
		Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
		byte[] encBytes = null;
		try {
			encBytes = cipher.doFinal(bytes);
		} catch (IllegalStateException e) {
			throw new GeneralException(e);
		} catch (IllegalBlockSizeException e) {
			throw new GeneralException(e);
		} catch (BadPaddingException e) {
			throw new GeneralException(e);
		}
		return encBytes;
	}

	public byte[] encrypt(SecretKey key, byte[] bytes, int off, int len) throws GeneralException {
		Cipher cipher = getCipher(key, Cipher.ENCRYPT_MODE);
		byte[] encBytes = null;
		try {
			encBytes = cipher.doFinal(bytes, off, len);
		} catch (IllegalStateException e) {
			throw new GeneralException(e);
		} catch (IllegalBlockSizeException e) {
			throw new GeneralException(e);
		} catch (BadPaddingException e) {
			throw new GeneralException(e);
		}
		return encBytes;
	}

	public byte[] decrypt(SecretKey key, byte[] bytes) throws GeneralException {
		Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
		byte[] decBytes = null;
		try {
			decBytes = cipher.doFinal(bytes);
		} catch (IllegalStateException e) {
			throw new GeneralException(e);
		} catch (IllegalBlockSizeException e) {
			throw new GeneralException(e);
		} catch (BadPaddingException e) {
			throw new GeneralException(e);
		}
		return decBytes;
	}

	public byte[] decrypt(SecretKey key, byte[] bytes, int off, int len) throws GeneralException {
		Cipher cipher = getCipher(key, Cipher.DECRYPT_MODE);
		byte[] decBytes = null;
		try {
			decBytes = cipher.doFinal(bytes, off, len);
		} catch (IllegalStateException e) {
			throw new GeneralException(e);
		} catch (IllegalBlockSizeException e) {
			throw new GeneralException(e);
		} catch (BadPaddingException e) {
			throw new GeneralException(e);
		}
		return decBytes;
	}

	// return a cipher for a key - DESede/CBC/PKCS5Padding IV = 0
	protected Cipher getCipher(SecretKey key, int mode) throws GeneralException {
		byte[] zeros = { 0, 0, 0, 0, 0, 0, 0, 0 };
		IvParameterSpec iv = new IvParameterSpec(zeros);

		Cipher encCipher = null;
		try {
			encCipher = Cipher.getInstance(transformation);
		} catch (NoSuchAlgorithmException e) {
			throw new GeneralException(e);
		} catch (NoSuchPaddingException e) {
			throw new GeneralException(e);
		}
		try {
			encCipher.init(mode, key, iv);
		} catch (InvalidKeyException e) {
			throw new GeneralException(e);
		} catch (InvalidAlgorithmParameterException e) {
			throw new GeneralException(e);
		}
		return encCipher;
	}
	
	
	public   SecretKey getDesKey(byte[] rawKey) throws GeneralException {
		// load the raw key
		if (rawKey.length > 0) {
			SecretKeyFactory skf = null;
			try {
				skf = SecretKeyFactory.getInstance(algorithm);
			} catch (NoSuchAlgorithmException e) {
				throw new GeneralException(e);
			}			
			
			DESedeKeySpec desedeSpec1 = null;
			try {
				desedeSpec1 = new DESedeKeySpec(rawKey);
			} catch (InvalidKeyException e) {
				throw new GeneralException(e);
			}

			// create the SecretKey Object
			SecretKey key = null;
			try {
				key = skf.generateSecret(desedeSpec1);
			} catch (InvalidKeySpecException e) {
				throw new GeneralException(e);
			}
			return key;
		} else {
			throw new GeneralException("Not a valid DESede key!");
		}
	}
}
